package com.csii.sys.config;

import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.core.parser.ISqlParserFilter;
import com.baomidou.mybatisplus.core.parser.SqlParserHelper;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
import com.csii.core.util.TenantContext;
import com.csii.sys.config.mybatis.CustomerTenantParser;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.schema.Column;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.MetaObject;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Auther: ian
 */
@EnableTransactionManagement // 开启事务管理
@MapperScan("com.csii.*.mapper") // 扫描Mapper接口
@Configuration
@Slf4j
public class MybatisPlusConfig {

    /**
     * tenant_id 字段名
     */
    public static final String tenant_field = "tenant_id";

    /**
     * 有哪些表需要做多租户 这些表需要添加一个字段 ，字段名和tenant_field对应的值一样
     */
    private static final Set<String> tenantTable = new HashSet<>();
    @Autowired
    private DataSource dataSource;

    @PostConstruct
    public void initTenantTable(){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        try {
            DatabaseMetaData databaseMetaData= jdbcTemplate.getDataSource().getConnection().getMetaData();
            String db=databaseMetaData.getDatabaseProductName();
            String str=null;
            switch (db.toLowerCase()) {
                case ("mysql"):
                    str = String.format("select distinct table_name from information_schema.columns where table_schema = '%s' AND COLUMN_name = '%s'", ((com.mysql.cj.jdbc.DatabaseMetaData)databaseMetaData).getConnection().getCatalog(),tenant_field);
                    break;
                case("oracle"):
                    str = String.format("select distinct colstable.table_name as  table_name from user_tab_cols colstable where colstable.COLUMN_NAME='%s' order by colstable.table_name",tenant_field.toUpperCase());
                    break;
                case("postgresql"):
                    str = String.format("SELECT table_name FROM information_schema.columns WHERE table_schema = 'public' and column_name = '%s'",tenant_field);
                    break;
                case("sqlserver"):
                    str = String.format("select distinct NAME from  sysobjects where id in (select id from  syscolumns Where name='%s') ",tenant_field);
                    break;
            }
            List<String> tableNameList = jdbcTemplate.queryForList(str, String.class);
            tenantTable.addAll(tableNameList);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
    }

    /**
     * 多租户属于 SQL 解析部分，依赖 MP 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor().setLimit(-1);
        /*
         * 【测试多租户】 SQL 解析处理拦截器<br>
         * 这里固定写成住户 1 实际情况你可以从cookie读取，因此数据看不到 【 麻花藤 】 这条记录（ 注意观察 SQL ）<br>
         */
        List<ISqlParser> sqlParserList = new ArrayList<>();
        TenantSqlParser tenantSqlParser = new CustomerTenantParser();
        tenantSqlParser.setTenantHandler(new TenantHandler() {

            @Override
            public Expression getTenantId(boolean select) {
                String tenant_id = TenantContext.getTenant();
                return new StringValue(tenant_id);
            }
            @Override
            public String getTenantIdColumn() {
                return tenant_field;
            }

            @Override
            public boolean doTableFilter(String tableName) {
                //true则不加租户条件查询  false则加
                // return excludeTable.contains(tableName);
                if(TenantContext.getTenant() !=null && tenantTable.contains(tableName)){
                    return false;
                }
                return true;
            }

            private Expression in(String ids){
                final InExpression inExpression = new InExpression();
                inExpression.setLeftExpression(new Column(getTenantIdColumn()));
                final ExpressionList itemsList = new ExpressionList();
                final List<Expression> inValues = new ArrayList<>(2);
                for(String id:ids.split(",")){
                    inValues.add(new LongValue(id));
                }
                itemsList.setExpressions(inValues);
                inExpression.setRightItemsList(itemsList);
                return inExpression;
            }

        });

        sqlParserList.add(tenantSqlParser);
        paginationInterceptor.setSqlParserList(sqlParserList);
        paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {
            @Override
            public boolean doFilter(MetaObject metaObject) {
                MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);
                // 过滤自定义查询此时无租户信息约束【 麻花藤 】出现
                if ("com.baomidou.springboot.mapper.UserMapper.selectListBySQL".equals(ms.getId())) {
                    return true;
                }
                return false;
            }
        });
        return paginationInterceptor;
    }
//    /**
//     * mybatis-plus SQL执行效率插件【生产环境可以关闭】
//     */
//    @Bean
//    public PerformanceInterceptor performanceInterceptor() {
//        return new PerformanceInterceptor();
//    }
}
